import React, { ChangeEvent, useEffect, useState } from 'react';
import classNames from 'classnames';
import './style/index.less';
import { RadioGroupContext } from './Group';
import { RadioChangeEvent, RadioValueType, RadioType, RadioSliderType } from './interface';

export interface RadioProps {
  id?: string;
  name?: string;
  value?: RadioValueType;
  style?: React.CSSProperties;
  className?: string;
  children?: React.ReactNode;
  prefixCls?: string;
  checked?: boolean;
  defaultChecked?: boolean;
  disabled?: boolean;
  autoFocus?: boolean;
  onChange?: (e: RadioChangeEvent) => void;
  onClick?: React.MouseEventHandler<HTMLInputElement>;
  onMouseEnter?: React.MouseEventHandler<HTMLElement>;
  onMouseLeave?: React.MouseEventHandler<HTMLElement>;
  onKeyPress?: React.KeyboardEventHandler<HTMLElement>;
  onKeyDown?: React.KeyboardEventHandler<HTMLElement>;
  onFocus?: React.FocusEventHandler<HTMLInputElement>;
  onBlur?: React.FocusEventHandler<HTMLInputElement>;
}

const Radio = React.forwardRef<HTMLInputElement, RadioProps>((props, ref) => {
  const groupContext = React.useContext(RadioGroupContext);
  const {
    children,
    className,
    style,
    prefixCls = 'dt-radio',
    disabled: customDisabled,
    defaultChecked = false,
    onChange,
    value,
    ...reset
  } = props;

  const labelRef = React.useRef<HTMLLabelElement>(null);
  const isChecked = 'checked' in props ? props.checked : defaultChecked;
  const [checked, setChecked] = useState<boolean | undefined>(isChecked);
  let type: RadioType = 'default';
  let sliderStyle: RadioSliderType = 'outline';

  const radioProps: RadioProps = { ...reset };

  if (groupContext) {
    radioProps.disabled = groupContext.disabled || customDisabled;
    radioProps.checked = value === groupContext.value;
    radioProps.name = groupContext.name;
    type = groupContext.type || 'default';
    sliderStyle = groupContext.sliderStyle || 'outline';
  } else {
    radioProps.disabled = customDisabled;
    radioProps.checked = checked;
  }

  const handleOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (radioProps.disabled) {
      return;
    }
    if (!('checked' in props)) {
      setChecked(e.target.checked);
    }
    if (groupContext === null) {
      onChange?.({
        target: {
          ...e,
          checked: !checked,
        },
        stopPropagation: e.stopPropagation,
        preventDefault: e.preventDefault,
      });
    } else {
      groupContext.onChange?.({
        target: {
          ...e,
          value,
          checked: !checked,
        },
        stopPropagation: e.stopPropagation,
        preventDefault: e.preventDefault,
      });
    }
  };

  const handleLabel = (e: ChangeEvent<HTMLLabelElement>) => {
    if (radioProps.disabled || groupContext === null) {
      return;
    }
    const left = e.currentTarget.offsetLeft;
    const width = e.currentTarget.offsetWidth - e.currentTarget.clientLeft;
    groupContext?.currentTarget?.({
      left,
      width: `${width}px`,
    });
  };

  const initailLabel = (targetElement: HTMLElement) => {
    const left = targetElement?.offsetLeft;
    const width = targetElement?.offsetWidth - targetElement.clientLeft;
    groupContext?.currentTarget?.({
      left,
      width: `${width}px`,
    });
  };

  const classTypeRender = () => {
    switch (type) {
      case 'default':
        return `${prefixCls}`;
      case 'button':
      case 'slider':
        return `${prefixCls}-${type}`;
      default:
        break;
    }
  };

  const wrapperClassString = classNames(
    `${classTypeRender()}-wrapper`,
    {
      [`${classTypeRender()}-wrapper-checked`]: radioProps.checked,
      [`${classTypeRender()}-wrapper-disabled`]: radioProps.disabled,
      [`${classTypeRender()}-wrapper-solid`]: radioProps.checked && sliderStyle === 'solid',
    },
    className,
  );
  const radioClassString = classNames(`${classTypeRender()}`, {
    [`${classTypeRender()}-checked`]: radioProps.checked,
    [`${classTypeRender()}-disabled`]: radioProps.disabled,
  });

  useEffect(() => {
    if (groupContext !== null && type === 'slider') {
      const ele = labelRef.current;
      if (ele?.className.includes(`${classTypeRender()}-wrapper-checked`)) {
        initailLabel(ele);
      }
    }
  }, []);

  const renderTree = () => {
    switch (type) {
      case 'slider':
        return (
          <label className={wrapperClassString} onChange={handleLabel} ref={labelRef}>
            <span className={radioClassString}>
              <input
                type="radio"
                {...radioProps}
                className={`${classTypeRender()}-input`}
                onChange={handleOnChange}
                ref={ref}
              />
            </span>
            {children !== undefined ? <span>{children}</span> : null}
          </label>
        );
      default:
        return (
          <label className={wrapperClassString} style={style}>
            <span className={radioClassString}>
              <input
                type="radio"
                {...radioProps}
                className={`${classTypeRender()}-input`}
                onChange={handleOnChange}
              />
              <span className={`${classTypeRender()}-inner`}></span>
            </span>
            {children !== undefined ? <span>{children}</span> : null}
          </label>
        );
    }
  };

  return renderTree();
});

export default Radio;
